/*  ----------------------------------------------------------------------------
 *  Arello Mobile
 *  Fast 3d Engine
 *  ----------------------------------------------------------------------------
 * Except where otherwise noted, this work is licensed under
 * http://creativecommons.org/licenses/by/3.0
 */

#include "Plane.h"
#include "Sphere.h"
#include "Box.h"

namespace liba
{
namespace math
{

template< typename T >
Plane<T>::Plane( const Vector3<T> & normal, const T & offset )
:	normal( normal ),
	offset( offset )
{
	this->normal.normalize();
	plane_point = normal * offset;
}

template< typename T >
Plane<T>::Plane( const Vector3<T> & normal, const Vector3<T> & plane_point )
:	normal( normal )
{
	this->normal.normalize();
	offset = Vector3<T>::dot( plane_point, normal );
	this->plane_point = normal * offset;
}

template< typename T >
bool Plane<T>::intersects( const Sphere & sphere )const
{
	return fabs( distance( sphere.get_center() ) ) <= sphere.get_radius();
}

template< typename T >
bool Plane<T>::intersects( const Box & box )const
{
	double d = distance( box.get_center() );
	Vector3<T> box_extents = box.get_extents();
	double temp = box_extents.x * fabs( Vector3<T>::dot( normal, box.get_x_normal() ) );
	temp += box_extents.y * fabs( Vector3<T>::dot( normal, box.get_y_normal() ) );
	temp += box_extents.z * fabs( Vector3<T>::dot( normal, box.get_z_normal() ) );

	return fabs( d ) <= temp;
}

template< typename T >
T Plane<T>::distance( const Vector3<T> & vector )const
{
	return Vector3<T>::dot( vector, normal ) - offset;
}

template< typename T >
void Plane<T>::transform( const Matrix4<T> & transform )
{
	Matrix4<T> hre;//workaround internal compiler error
	plane_point = transform * plane_point;
	Matrix4<T> rotation = Matrix4<T>::translate( -transform.shift() ) * transform;
	normal = rotation * normal;
	offset = Vector3<T>::dot( plane_point, normal );
}

template< typename T >
const Vector3<T> Plane<T>::project_into_plane( const Vector3<T> & v )const
{
	double dot_prod = Vector3<T>::dot( normal, v );
	Vector3<T> nmlComp = normal * dot_prod;
	return v - nmlComp;
} 

} // namespace math
} // namespace liba


